package org.yuxiong.utils;
import java.awt.Image;
import   java.awt.image.BufferedImage;  
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;

@SuppressWarnings("unused")
public   class   ImageScale   {
	
	  private   int   width;  
	  private   int   height;  
	  private   int   scaleWidth;  
	  double   support   =   (double)   3.0;  
	  double   PI   =   (double)   3.14159265358978;  
	  double[]   contrib;  
	  double[]   normContrib;  
	  double[]   tmpContrib;  
	  int   startContrib,   stopContrib;  
	  int   nDots;  
	  int   nHalfDots;  
	   
	  /**  
	    *   Start:  
	    *   Use   Lanczos   filter   to   replace   the   original   algorithm   for   image   scaling.   Lanczos   improves   quality   of   the   scaled   image  
	    *   modify   by   :blade  
	    *   */  
	  public   BufferedImage   imageZoomOut(BufferedImage   srcBufferImage,int   w,   int   h)   { 
		  width   =   srcBufferImage.getWidth();  
		  height   =   srcBufferImage.getHeight();  
		  scaleWidth   =   w;  
		   
		  if   (DetermineResultSize(w,   h)   ==   1)   {  
		  return   srcBufferImage;  
		  }  
		  CalContrib();  
		  BufferedImage   pbOut   =   HorizontalFiltering(srcBufferImage,   w);  
		  BufferedImage   pbFinalOut   =   VerticalFiltering(pbOut,   h);  
		  return   pbFinalOut;
	  }  
	   
	  /**  
	    *   决定图像尺寸  
	    *   */  
	  private   int   DetermineResultSize(int   w,   int   h)   {  
	  double   scaleH,   scaleV;  
	  scaleH   =   (double)   w   /   (double)   width;  
	  scaleV   =   (double)   h   /   (double)   height;  
	  //需要判断一下scaleH，scaleV，不做放大操作  
	  if   (scaleH   >=   1.0   &&   scaleV   >=   1.0)   {  
	  return   1;  
	  }  
	  return   0;  
	   
	  }   //   end   of   DetermineResultSize()  
	   
	  private   double   Lanczos(int   i,   int   inWidth,   int   outWidth,   double   Support)   {  
	  double   x;  
	   
	  x   =   (double)   i   *   (double)   outWidth   /   (double)   inWidth;  
	   
	  return   Math.sin(x   *   PI)   /   (x   *   PI)   *   Math.sin(x   *   PI   /   Support)  
	  /   (x   *   PI   /   Support);  
	   
	  }   //   end   of   Lanczos()  
	   
	  //  
	  //       Assumption:   same   horizontal   and   vertical   scaling   factor  
	  //  
	  private   void   CalContrib()   {  
	  nHalfDots   =   (int)   ((double)   width   *   support   /   (double)   scaleWidth);  
	  nDots   =   nHalfDots   *   2   +   1;  
	  try   {  
	  contrib   =   new   double[nDots];  
	  normContrib   =   new   double[nDots];  
	  tmpContrib   =   new   double[nDots];  
	  }   catch   (Exception   e)   {  
	  System.out.println("init   contrib,normContrib,tmpContrib"   +   e);  
	  }  
	   
	  int   center   =   nHalfDots;  
	  contrib[center]   =   1.0;  
	   
	  double   weight   =   0.0;  
	  int   i   =   0;  
	  for   (i   =   1;   i   <=   center;   i++)   {  
	  contrib[center   +   i]   =   Lanczos(i,   width,   scaleWidth,   support);  
	  weight   +=   contrib[center   +   i];  
	  }  
	   
	  for   (i   =   center   -   1;   i   >=   0;   i--)   {  
	  contrib[i]   =   contrib[center   *   2   -   i];  
	  }  
	   
	  weight   =   weight   *   2   +   1.0;  
	   
	  for   (i   =   0;   i   <=   center;   i++)   {  
	  normContrib[i]   =   contrib[i]   /   weight;  
	  }  
	   
	  for   (i   =   center   +   1;   i   <   nDots;   i++)   {  
	  normContrib[i]   =   normContrib[center   *   2   -   i];  
	  }  
	  }   //   end   of   CalContrib()  
	   
	  //处理边缘  
	  private   void   CalTempContrib(int   start,   int   stop)   {  
	  double   weight   =   0;  
	   
	  int   i   =   0;  
	  for   (i   =   start;   i   <=   stop;   i++)   {  
	  weight   +=   contrib[i];  
	  }  
	   
	  for   (i   =   start;   i   <=   stop;   i++)   {  
	  tmpContrib[i]   =   contrib[i]   /   weight;  
	  }  
	   
	  }   //   end   of   CalTempContrib()  
	   
	  private   int   GetRedValue(int   rgbValue)   {  
	  int   temp   =   rgbValue   &   0x00ff0000;  
	  return   temp   >>   16;  
	  }  
	   
	  private   int   GetGreenValue(int   rgbValue)   {  
	  int   temp   =   rgbValue   &   0x0000ff00;  
	  return   temp   >>   8;  
	  }  
	   
	  private   int   GetBlueValue(int   rgbValue)   {  
	  return   rgbValue   &   0x000000ff;  
	  }  
	   
	  private   int   ComRGB(int   redValue,   int   greenValue,   int   blueValue)   {  
	   
	  return   (redValue   <<   16)   +   (greenValue   <<   8)   +   blueValue;  
	  }  
	   
	  //行水平滤波  
	  private   int   HorizontalFilter(BufferedImage   bufImg,   int   startX,   int   stopX,  
	  int   start,   int   stop,   int   y,   double[]   pContrib)   {  
	  double   valueRed   =   0.0;  
	  double   valueGreen   =   0.0;  
	  double   valueBlue   =   0.0;  
	  int   valueRGB   =   0;  
	  int   i,   j;  
	   
	  for   (i   =   startX,   j   =   start;   i   <=   stopX;   i++,   j++)   {  
	  valueRGB   =   bufImg.getRGB(i,   y);  
	   
	  valueRed   +=   GetRedValue(valueRGB)   *   pContrib[j];  
	  valueGreen   +=   GetGreenValue(valueRGB)   *   pContrib[j];  
	  valueBlue   +=   GetBlueValue(valueRGB)   *   pContrib[j];  
	  }  
	   
	  valueRGB   =   ComRGB(Clip((int)   valueRed),   Clip((int)   valueGreen),  
	  Clip((int)   valueBlue));  
	  return   valueRGB;  
	   
	  }   //   end   of   HorizontalFilter()  
	   
	 //图片水平滤波  
	  private   BufferedImage   HorizontalFiltering(BufferedImage   bufImage,   int   iOutW)   {  
	  int   dwInW   =   bufImage.getWidth();  
	  int   dwInH   =   bufImage.getHeight();  
	  int   value   =   0;  
	  BufferedImage   pbOut   =   new   BufferedImage(iOutW,   dwInH,  
	  BufferedImage.TYPE_INT_RGB);  
	   
	  for   (int   x   =   0;   x   <   iOutW;   x++)   {  
	   
	  int   startX;  
	  int   start;  
	  int   X   =   (int)   (((double)   x)   *   ((double)   dwInW)   /   ((double)   iOutW)   +   0.5);  
	  int   y   =   0;  
	   
	  startX   =   X   -   nHalfDots;  
	  if   (startX   <   0)   {  
	  startX   =   0;  
	  start   =   nHalfDots   -   X;  
	  }   else   {  
	  start   =   0;  
	  }  
	   
	  int   stop;  
	  int   stopX   =   X   +   nHalfDots;  
	  if   (stopX   >   (dwInW   -   1))   {  
	  stopX   =   dwInW   -   1;  
	  stop   =   nHalfDots   +   (dwInW   -   1   -   X);  
	  }   else   {  
	  stop   =   nHalfDots   *   2;  
	  }  
	   
	  if   (start   >   0   ||   stop   <   nDots   -   1)   {  
	  CalTempContrib(start,   stop);  
	  for   (y   =   0;   y   <   dwInH;   y++)   {  
	  value   =   HorizontalFilter(bufImage,   startX,   stopX,   start,  
	  stop,   y,   tmpContrib);  
	  pbOut.setRGB(x,   y,   value);  
	  }  
	  }   else   {  
	  for   (y   =   0;   y   <   dwInH;   y++)   {  
	  value   =   HorizontalFilter(bufImage,   startX,   stopX,   start,  
	  stop,   y,   normContrib);  
	  pbOut.setRGB(x,   y,   value);  
	  }  
	  }  
	  }  
	   
	  return   pbOut;  
	   
	  }   //   end   of   HorizontalFiltering()  
	   
	  private   int   VerticalFilter(BufferedImage   pbInImage,   int   startY,   int   stopY,  
	  int   start,   int   stop,   int   x,   double[]   pContrib)   {  
	  double   valueRed   =   0.0;  
	  double   valueGreen   =   0.0;  
	  double   valueBlue   =   0.0;  
	  int   valueRGB   =   0;  
	  int   i,   j;  
	   
	  for   (i   =   startY,   j   =   start;   i   <=   stopY;   i++,   j++)   {  
	  valueRGB   =   pbInImage.getRGB(x,   i);  
	   
	  valueRed   +=   GetRedValue(valueRGB)   *   pContrib[j];  
	  valueGreen   +=   GetGreenValue(valueRGB)   *   pContrib[j];  
	  valueBlue   +=   GetBlueValue(valueRGB)   *   pContrib[j];  
	  //     System.out.println(valueRed+"->"+Clip((int)valueRed)+"<-");  
	  //  
	  //     System.out.println(valueGreen+"->"+Clip((int)valueGreen)+"<-");  
	  //     System.out.println(valueBlue+"->"+Clip((int)valueBlue)+"<-"+"-->");  
	  }  
	   
	  valueRGB   =   ComRGB(Clip((int)   valueRed),   Clip((int)   valueGreen),  
	  Clip((int)   valueBlue));  
	  //       System.out.println(valueRGB);  
	  return   valueRGB;  
	   
	  }   //   end   of   VerticalFilter()  
	   
	  private   BufferedImage   VerticalFiltering(BufferedImage   pbImage,   int   iOutH)   {  
	  int   iW   =   pbImage.getWidth();  
	  int   iH   =   pbImage.getHeight();  
	  int   value   =   0;  
	  BufferedImage   pbOut   =   new   BufferedImage(iW,   iOutH,  
	  BufferedImage.TYPE_INT_RGB);  
	   
	  for   (int   y   =   0;   y   <   iOutH;   y++)   {  
	   
	  int   startY;  
	  int   start;  
	  int   Y   =   (int)   (((double)   y)   *   ((double)   iH)   /   ((double)   iOutH)   +   0.5);  
	   
	  startY   =   Y   -   nHalfDots;  
	  if   (startY   <   0)   {  
	  startY   =   0;  
	  start   =   nHalfDots   -   Y;  
	  }   else   {  
	  start   =   0;  
	  }  
	   
	  int   stop;  
	  int   stopY   =   Y   +   nHalfDots;  
	  if   (stopY   >   (int)   (iH   -   1))   {  
	  stopY   =   iH   -   1;  
	  stop   =   nHalfDots   +   (iH   -   1   -   Y);  
	  }   else   {  
	  stop   =   nHalfDots   *   2;  
	  }  
	   
	  if   (start   >   0   ||   stop   <   nDots   -   1)   {  
	  CalTempContrib(start,   stop);  
	  for   (int   x   =   0;   x   <   iW;   x++)   {  
	  value   =   VerticalFilter(pbImage,   startY,   stopY,   start,   stop,  
	  x,   tmpContrib);  
	  pbOut.setRGB(x,   y,   value);  
	  }  
	  }   else   {  
	  for   (int   x   =   0;   x   <   iW;   x++)   {  
	  value   =   VerticalFilter(pbImage,   startY,   stopY,   start,   stop,  
	  x,   normContrib);  
	  pbOut.setRGB(x,   y,   value);  
	  }  
	  }  
	   
	  }  
	   
	  return   pbOut;  
	   
	  }   //   end   of   VerticalFiltering()  
	   
	  int   Clip(int   x)   {  
	  if   (x   <   0)  
	  return   0;  
	  if   (x   >   255)  
	  return   255;  
	  return   x;  
	  }  
	   
	  /**  
	    *   End:  
	    *   Use   Lanczos   filter   to   replace   the   original   algorithm   for   image   scaling.   Lanczos   improves   quality   of   the   scaled   image  
	    *   modify   by   :blade  
	 * @throws IOException 
	    *   */  
	   
	   public static void main(String[] args) throws IOException{
		   ImageScale is = new ImageScale();

		   BufferedImage srcBufferImage= javax.imageio.ImageIO.read(new File("D:\\img.mymusic.com\\images\\singer\\2008\\3\\22\\16\\20080322165946.jpg"));
		   BufferedImage tag = is.imageZoomOut(srcBufferImage,57,57);
		   
		   BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:\\img.mymusic.com\\images\\singer\\2008\\3\\22\\16\\20080322165946_sis.jpg"));
           JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(bos);    //������С���ͼ
           encoder.encode(tag);
           bos.close();
	   }
}   
